package com.ynet.middleground.riskmanage.model;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.dozer.Mapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ifp.util.core.DateUtil;
import com.ynet.core.common.BaseReqObj;
import com.ynet.core.exception.BusinessException;
import com.ynet.file.starter.FileServiceConfiguration;
import com.ynet.host.HostConstants;
import com.ynet.middleground.riskmanage.bean.InvoiceStatisticQueryReqPager;
import com.ynet.middleground.riskmanage.bean.InvoiceValidateOCRReq;
import com.ynet.middleground.riskmanage.bean.InvoiceValidateReq;
import com.ynet.middleground.riskmanage.dao.*;
import com.ynet.middleground.riskmanage.dto.*;
import com.ynet.middleground.riskmanage.entity.*;
import com.ynet.middleground.riskmanage.external.zbj.ZbjConfig;
import com.ynet.middleground.riskmanage.utils.ApiUtil;
import com.ynet.middleground.riskmanage.utils.BeanUtil;
import com.ynet.middleground.riskmanage.utils.FileUtil;

/**
 * @author liulx
 * @description 发票验证业务处理
 * @date 2020-07-31 15:45
 */
@Component
public class InvoiceValidModel {

    @Autowired
    private ZbjConfig zbjConfig;

    @Autowired
    private Mapper mapper;

    @Autowired
    private ZbjInvoiceLogMapper logMapper;

    @Autowired
    private ZbjInvoiceBaseMapper baseMapper;

    @Autowired
    private ZbjInvoiceUnifiedGoodsMapper unifiedGoodsMapper;

    @Autowired
    private ZbjInvoiceMotorVehiclesGoodsMapper motorVehiclesGoodsMapper;

    @Autowired
    private ZbjInvoiceUsedCarGoodsMapper usedCarGoodsMapper;

    @Autowired
    private ApiUtil apiUtil;

    @Autowired
    FileServiceConfiguration fileServiceConfiguration;

    /**
     * 日志打印显示的名字
     */
    private static final String LOG_NAME = "八戒财税";

    /**
     * api 接口版本
     */
    private static final String API_VERSION = "v2";

    /**
     * 发票基础查验地址
     */
    private static final String INVOICE_BASE_QUERY = API_VERSION + "/invoice/query";

    /**
     * OCR 发票查验
     */
    private static final String INVOICE_OCR_QUERY = API_VERSION + "/invoice/ocr";

    /**
     * TODO 注意：临时测试使用
     * 
     * @param headMap
     * @param params
     * @param url
     * @param httpMethod
     * @return
     */
    public JSONObject sendApi(Map<String, String> headMap, Map<String, Object> params, String url, String httpMethod) {
        // TODO： 专用临时测试，完后删除
        String jsonString =
            "{\"success\":true,\"code\":0,\"data\":{\"fplx\":\"01\",\"fpdm\":\"115001021001\",\"fphm\":\"38790143\",\"kprq\":\"20200601\",\"xfMc\":\"北京中软融鑫计算机系统工程有限公司\",\"fplxName\":\"增值税专用发票\",\"sfMc\":\"北京\",\"sfCode\":\"1100\",\"xfNsrsbh\":\"91110108101194908R\",\"xfContact\":\"北京市海淀区学院南路55号中软大厦1号楼12层 010-51527500\",\"xfBank\":\"交通银行北京农科院支行110060435012015034766\",\"gfMc\":\"青岛港资产管理有限公司\",\"gfNsrsbh\":\"91370203MA3C7GBK9N\",\"gfContact\":\"青岛市市北区港华路7号21楼 0532-82985309\",\"gfBank\":\"青岛银行港口支行 802790288888898\",\"code\":\"64525550600870020329\",\"num\":\"661516975211\",\"del\":\"0\",\"taxamount\":\"3772.08\",\"goodsamount\":\"62867.92\",\"sumamount\":\"66640\",\"quantityAmount\":0.7,\"remark\":\"\",\"isGoodsList\":\"N\",\"goodsData\":[{\"name\":\"*信息技术服务*技术维护费1\",\"spec\":\"无\",\"unit\":\"无\",\"amount\":\"0.7\",\"priceUnit\":\"89811.320754716981132\",\"priceSum\":\"62867.92\",\"taxRate\":\"6.0\",\"taxSum\":\"3772.08\"},{\"name\":\"*信息技术服务*技术维护费2\",\"spec\":\"无\",\"unit\":\"无\",\"amount\":\"0.7\",\"priceUnit\":\"89811.320754716981132\",\"priceSum\":\"62867.92\",\"taxRate\":\"6.0\",\"taxSum\":\"3772.08\"},{\"name\":\"*信息技术服务*技术维护费3\",\"spec\":\"无\",\"unit\":\"无\",\"amount\":\"0.7\",\"priceUnit\":\"89811.320754716981132\",\"priceSum\":\"62867.92\",\"taxRate\":\"6.0\",\"taxSum\":\"3772.08\"},{\"name\":\"*信息技术服务*技术维护费4\",\"spec\":\"无\",\"unit\":\"无\",\"amount\":\"0.7\",\"priceUnit\":\"89811.320754716981132\",\"priceSum\":\"62867.92\",\"taxRate\":\"6.0\",\"taxSum\":\"3772.08\"}],\"queryCount\":\"6\",\"updateTime\":\"1596183644615\"}}";

        JSONObject apiResult = JSONObject.parseObject(jsonString);
        return apiResult;
    }

    /**
     * 获取公共参数
     *
     * @param appKey 授权应用的 appKey
     * @return 签名字符串
     */
    private List<NameValuePair> getParams(String appKey) {
        if (appKey == null) {
            throw new NullPointerException();
        }
        List<NameValuePair> params = new ArrayList<>();
        params.add(new BasicNameValuePair("X-CS-Authorization", "HMAC-SHA256"));
        params.add(new BasicNameValuePair("X-CS-Key", appKey));
        params.add(new BasicNameValuePair("X-CS-Nonce", UUID.randomUUID().toString()));
        params.add(new BasicNameValuePair("X-CS-Timestamp", "" + System.currentTimeMillis() / 1000L));
        params.add(new BasicNameValuePair("X-CS-Version", API_VERSION));
        return params;
    }

    /**
     * 获取签名字符串 跟据公共参数的集合，按名称升序排列后用‘|’拼接
     *
     * @param key 授权应用的 appKey
     * @param data 请求头 signString 的值
     * @return 签名字符串
     */
    public String getSignature(final String key, final String data)
        throws NoSuchAlgorithmException, InvalidKeyException {
        if (key == null || data == null) {
            throw new NullPointerException();
        }
        final String HMAC_SHA256 = "HmacSHA256";
        final Mac hMacSHA256 = Mac.getInstance(HMAC_SHA256);
        byte[] hmacKeyBytes = key.getBytes(StandardCharsets.UTF_8);
        final SecretKeySpec secretKey = new SecretKeySpec(hmacKeyBytes, HMAC_SHA256);
        hMacSHA256.init(secretKey);
        byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
        byte[] res = hMacSHA256.doFinal(dataBytes);
        return Base64.getEncoder().encodeToString(res);
    }

    /**
     * 获取请求头信息
     * 
     * @return
     */
    public Map<String, String> getHeadMap() throws NoSuchAlgorithmException, InvalidKeyException {
        Map<String, String> headMap = new HashMap<>(8);
        List<NameValuePair> params = getParams(zbjConfig.getAppKey());
        final String splitor = "|";
        StringBuilder signBuilder = new StringBuilder(HostConstants.HTTP_METHOD_POST + splitor);
        for (NameValuePair pair : params) {
            String key = pair.getName();
            String value = pair.getValue();
            headMap.put(key, value);
            signBuilder.append(key + "=" + value + splitor);
        }
        String signString = signBuilder.substring(0, signBuilder.length() - 1);
        String signature = getSignature(zbjConfig.getAppSecret(), signString);
        headMap.put("X-CS-Signature", signature);
        return headMap;
    }

    /**
     * 发票基础查验
     * 
     * @param req 发票基础查验请求信息 {@link InvoiceValidateReq}
     * @return 发票信息
     * @throws InvalidKeyException
     * @throws NoSuchAlgorithmException
     */
    public InvoiceInfoDTO baseQuery(InvoiceValidateReq req) throws InvalidKeyException, NoSuchAlgorithmException {
        Map<String, Object> params = new HashMap<>(8);
        // =========================================全电发票======================================
        if (req.getFphm().length() == 20) {
            if (!StringUtils.isEmpty(req.getFpdm())) {
                throw new BusinessException("全电发票请勿上传发票代码", "ECCT0001");
            }
            if (StringUtils.isEmpty(req.getJshj())) {
                throw new BusinessException("全电发票请上传价税合计", "ECCT0001");
            }
            params.put("fphm", req.getFphm());
            params.put("kprq", req.getKprq());
            params.put("jshj", req.getJshj());

        } else {
            // =========================================非全电发票=======================================
            if (StringUtils.isEmpty(req.getFpdm())) {
                throw new BusinessException("请上传发票代码", "ECCT0001");
            }
            params.put("fpdm", req.getFpdm());
            params.put("fphm", req.getFphm());
            params.put("kprq", req.getKprq());
            params.put("checkCode", req.getCheckCode());
            params.put("noTaxAmount", req.getNoTaxAmount());
        }

        // 方法开始执行的时间
        long startTime = System.currentTimeMillis();
        // TODO: 测试专用
        // JSONObject jsonObject = sendApi(getHeadMap(), params, INVOICE_BASE_QUERY, HostConstants.HTTP_METHOD_POST);
        JSONObject jsonObject = apiUtil.sendApiLog("6001", zbjConfig.getServerUrl() + INVOICE_BASE_QUERY, getHeadMap(),
            params, HostConstants.HTTP_METHOD_POST, LOG_NAME, req);
        // 记录方法正常执行后时间
        long methodEnd = System.currentTimeMillis();
        Boolean success = jsonObject.getBoolean("success");
        Integer code = jsonObject.getInteger("code");
        ZbjInvoiceLog invoiceLog = new ZbjInvoiceLog();
        invoiceLog.setServiceStatus((success && code == 0));
        invoiceLog.setType("0");
        invoiceLog.setRequestMsg(JSON.toJSONString(params));
        invoiceLog.setResponseMsg(jsonObject.toJSONString());
        invoiceLog.setResDate(LocalDateTime.now());
        invoiceLog.setCostTime(Math.toIntExact((methodEnd - startTime)));
        invoiceLog.setChannel(req.getChannel());
        invoiceLog.setGmtCreate(LocalDateTime.now());
        invoiceLog.setCreateBy(req.getOperationUserId());
        invoiceLog.setGmtModified(LocalDateTime.now());
        invoiceLog.setModifiedBy(req.getOperationUserId());
        logMapper.insert(invoiceLog);

        String message = jsonObject.getString("message");
        if (code != 0) {
            throw new BusinessException(message, String.valueOf(code));
        }
        return saveInvoiceInfo(invoiceLog.getId(), req.getFpdm(), req.getFphm(), jsonObject, req);

    }

    /**
     * OCR 发票查验
     *
     * @param req 发票基础查验请求信息 {@link InvoiceValidateOCRReq}
     * @return 发票信息
     * @throws InvalidKeyException
     * @throws NoSuchAlgorithmException
     */
    public InvoiceInfoDTO ocrQuery(InvoiceValidateOCRReq req) throws InvalidKeyException, NoSuchAlgorithmException {
        String endpoint = fileServiceConfiguration.getConfigs().get(0).getOssConfig().getEndpoint();
        String url = FileUtil.getOssFullUrl(endpoint, req.getUrl());
        String suffix = FileUtil.getFileSuffix(url);
        if (StringUtils.isBlank(suffix)) {
            throw new BusinessException("文件后缀错误", "ECRM0002");
        }
        File file = FileUtil.getFileByUrl(url, "." + suffix);
        String imgBase64 = Base64.getEncoder().encodeToString(FileUtil.fileToByte(file));
        Map<String, Object> params = new HashMap<>(2);
        params.put("img", imgBase64);
        params.put("iscar", req.getIscar());

        // 方法开始执行的时间
        long startTime = System.currentTimeMillis();
        // JSONObject jsonObject = sendApi(getHeadMap(), params, INVOICE_OCR_QUERY, HostConstants.HTTP_METHOD_POST);
        JSONObject jsonObject = apiUtil.sendApiLog("6002", zbjConfig.getServerUrl() + INVOICE_OCR_QUERY, getHeadMap(),
            params, HostConstants.HTTP_METHOD_POST, LOG_NAME, req);
        // 记录方法正常执行后时间
        long methodEnd = System.currentTimeMillis();
        Boolean success = jsonObject.getBoolean("success");
        Integer code = jsonObject.getInteger("code");
        ZbjInvoiceLog invoiceLog = new ZbjInvoiceLog();
        if (!success || code != 0) {
            invoiceLog.setServiceStatus(success);
        }
        invoiceLog.setType("1");
        invoiceLog.setResponseMsg(jsonObject.toJSONString());
        invoiceLog.setRequestMsg(JSON.toJSONString(params));
        invoiceLog.setCostTime(Math.toIntExact((methodEnd - startTime)));
        invoiceLog.setResDate(LocalDateTime.now());
        invoiceLog.setGmtCreate(LocalDateTime.now());
        invoiceLog.setChannel(req.getChannel());
        invoiceLog.setModifiedBy(req.getOperationUserId());
        invoiceLog.setGmtModified(LocalDateTime.now());
        invoiceLog.setCreateBy(req.getOperationUserId());
        logMapper.insert(invoiceLog);

        String message = jsonObject.getString("message");
        if (code != 0) {
            throw new BusinessException(message, String.valueOf(code));
        }
        // OCR 识别后才能获取到发票号码
        return saveInvoiceInfo(invoiceLog.getId(), null, null, jsonObject, req);
    }

    /**
     * 发票统计查询，渠道专用
     * 
     * @param reqPager 查询请求信息
     * @return 统计查询结果集合
     */
    public List<InvoiceStatisticDTO> tatisticQueryForChannel(InvoiceStatisticQueryReqPager reqPager) {
        if (reqPager.getServiceName() != null) {
            if (reqPager.getServiceName() != 0 && reqPager.getServiceName() != 1) {
                throw new BusinessException("接口名称数值有误", "ECCT0100");
            }
        }
        if (StringUtils.isBlank(reqPager.getQueryChannel())) {
            throw new BusinessException("查询渠道不能为空", "ECRM0001");
        }
        if (reqPager.getPagerInfo().getPageNum() <= 0) {
            throw new BusinessException("pageNum 必须从1开始递增", "ECRM0001");
        }
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DateUtil.FORTER_DATE);
        if (StringUtils.isNotBlank(reqPager.getRequestTimeStart())) {
            try {
                simpleDateFormat.parse(reqPager.getRequestTimeStart());
                reqPager.setRequestTimeStart(reqPager.getRequestTimeStart() + " 00:00:00");
            } catch (ParseException e) {
                throw new BusinessException("调用时间起格式不正确", "ECRM0003");
            }
        }
        if (StringUtils.isNotBlank(reqPager.getRequestTimeEnd())) {
            try {
                simpleDateFormat.parse(reqPager.getRequestTimeEnd());
                reqPager.setRequestTimeEnd(reqPager.getRequestTimeEnd() + " 23:59:59");
            } catch (ParseException e) {
                throw new BusinessException("调用时间止格式不正确", "ECRM0003");
            }
        }
        Long queryCount = logMapper.tatisticQueryCount(reqPager);
        reqPager.getPagerInfo().setTotal(queryCount);
        return logMapper.tatisticQuery(reqPager, reqPager.getPagerInfo());
    }

    /**
     * 发票统计查询，内管专用
     *
     * @param reqPager 查询请求信息
     * @return 统计查询结果集合
     */
    public List<InvoiceStatisticDTO> tatisticQueryForPortAdmin(InvoiceStatisticQueryReqPager reqPager) {
        if (reqPager.getServiceName() != null) {
            if (reqPager.getServiceName() != 0 && reqPager.getServiceName() != 1) {
                throw new BusinessException("接口名称数值有误", "ECCT0100");
            }
        }
        if (reqPager.getPagerInfo().getPageNum() <= 0) {
            throw new BusinessException("pageNum 必须从1开始递增", "ECRM0001");
        }
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DateUtil.FORTER_DATE);
        if (StringUtils.isNotBlank(reqPager.getRequestTimeStart())) {
            try {
                simpleDateFormat.parse(reqPager.getRequestTimeStart());
                reqPager.setRequestTimeStart(reqPager.getRequestTimeStart() + " 00:00:00");
            } catch (ParseException e) {
                throw new BusinessException("调用时间起格式不正确", "ECRM0003");
            }
        }
        if (StringUtils.isNotBlank(reqPager.getRequestTimeEnd())) {
            try {
                simpleDateFormat.parse(reqPager.getRequestTimeEnd());
                reqPager.setRequestTimeEnd(reqPager.getRequestTimeEnd() + " 23:59:59");
            } catch (ParseException e) {
                throw new BusinessException("调用时间止格式不正确", "ECRM0003");
            }
        }
        Long queryCount = logMapper.tatisticQueryCount(reqPager);
        reqPager.getPagerInfo().setTotal(queryCount);
        return logMapper.tatisticQuery(reqPager, reqPager.getPagerInfo());
    }

    /**
     * 保存发票信息至数据库
     * 
     * @param reqId 日志记录 id
     * @param fpdm 发票代码，用来判断发票类型
     *            {@see https://open.cs.zbj.com/docs/v2/invoice.html#%E9%99%84%E5%BD%95-%E6%A0%B9%E6%8D%AE%E5%8F%91%E7%A5%A8%E4%BB%A3%E7%A0%81%E5%88%A4%E6%96%AD%E5%8F%91%E7%A5%A8%E7%B1%BB%E5%9E%8B}
     * @param fphm 发票号码
     * @param jsonObjectSource 八戒 api 接口返回的发票 json 数据
     * @param req 基础请求类
     */
    @Transactional(rollbackFor = Exception.class)
    public InvoiceInfoDTO saveInvoiceInfo(Integer reqId, String fpdm, String fphm, JSONObject jsonObjectSource,
        BaseReqObj req) {
        InvoiceInfoDTO invoiceInfoDTO = new InvoiceInfoDTO();
        // 封装发票基本信息
        JSONObject jsonObject = jsonObjectSource.getJSONObject("data");
        ZbjInvoiceBase zbjInvoiceBase = jsonObject.toJavaObject(ZbjInvoiceBase.class);
        zbjInvoiceBase.setReqId(reqId);
        zbjInvoiceBase.setChannel(req.getChannel());
        zbjInvoiceBase.setGmtCreate(LocalDateTime.now());
        zbjInvoiceBase.setCreateBy(req.getOperationUserId());
        zbjInvoiceBase.setGmtModified(LocalDateTime.now());
        zbjInvoiceBase.setModifiedBy(req.getOperationUserId());
        JSONObject goodsTotalInfo = jsonObject.getJSONObject("goodsTotalInfo");
        if (goodsTotalInfo != null) {
            zbjInvoiceBase.setName(goodsTotalInfo.getString("name"));
            zbjInvoiceBase.setSpec(goodsTotalInfo.getString("spec"));
            zbjInvoiceBase.setUnit(goodsTotalInfo.getString("unit"));
            zbjInvoiceBase.setAmount(goodsTotalInfo.getString("amount"));
            zbjInvoiceBase.setPriceUnit(goodsTotalInfo.getString("priceUnit"));
            zbjInvoiceBase.setPriceSum(goodsTotalInfo.getString("priceSum"));
            zbjInvoiceBase.setTaxRate(goodsTotalInfo.getString("taxRate"));
            zbjInvoiceBase.setTaxSum(goodsTotalInfo.getString("taxSum"));
        }
        baseMapper.insert(zbjInvoiceBase);
        ZbjInvoiceBaseDTO baseDTO = mapper.map(zbjInvoiceBase, ZbjInvoiceBaseDTO.class);
        // 如果此时 fpdm、fphm 为空，说明为 ocr 识别，要从接口响应结果中获取发票发票代码、发票号码
        if (StringUtils.isBlank(fpdm) && StringUtils.isBlank(fphm)) {
            fpdm = jsonObject.getString("fpdm");
            fphm = jsonObject.getString("fphm");
        }

        // =========================================全电发票======================================
        if (fphm.length() == 20) {
            // 全电发票的响应结果，相当于增值税专用发票(01),增值税普通发票(04),增值税电子专用发票(08),增值税电子普通发票(10)板块,走统一发票信息板块逻辑。
            // {@see https://open.cs.zbj.com/docs/v2/invoice.html}
            List<ZbjInvoiceUnifiedGoodsDTO> unifiedGoodsList =
                saveGeneralGoods(zbjInvoiceBase.getId(), jsonObject, req);
            invoiceInfoDTO.setUnifiedGoodsList(unifiedGoodsList);
        }
        // =========================================非全电发票=======================================
        if (fphm.length() != 20) {
            // 判断发票种类，二手车发票明细、机动车发票明细单独保存，其余类型发票统一保存
            if (fpdm.length() == 12) {
                // 15 二手车销售统一发票
                if (fpdm.charAt(0) == '0' && "17".equals(fpdm.substring(10, 12))) {
                    List<ZbjInvoiceUsedCarGoodsDTO> usedCarGoodsList =
                        saveUsedCarGoods(zbjInvoiceBase.getId(), jsonObject, req);
                    invoiceInfoDTO.setUsedCarGoodsList(usedCarGoodsList);
                } else if (fpdm.charAt(0) != '0' && "2".equals(fpdm.substring(7, 8))) {
                    // 03 机动车销售统一发票
                    List<ZbjInvoiceMotorVehiclesGoodsDTO> motorVehiclesGoodsList =
                        saveMotorVehiclesGoods(zbjInvoiceBase.getId(), jsonObject, req);
                    invoiceInfoDTO.setMotorVehiclesGoodsList(motorVehiclesGoodsList);
                } else {
                    // 统一发票信息
                    List<ZbjInvoiceUnifiedGoodsDTO> unifiedGoodsList =
                        saveGeneralGoods(zbjInvoiceBase.getId(), jsonObject, req);
                    invoiceInfoDTO.setUnifiedGoodsList(unifiedGoodsList);
                }
            } else {
                // 统一发票信息
                List<ZbjInvoiceUnifiedGoodsDTO> unifiedGoodsList =
                    saveGeneralGoods(zbjInvoiceBase.getId(), jsonObject, req);
                invoiceInfoDTO.setUnifiedGoodsList(unifiedGoodsList);
            }
        }

        invoiceInfoDTO.setInvoiceBase(baseDTO);
        return invoiceInfoDTO;
    }

    /**
     * 保存发票货物详情信息：统一发票明细信息，除机动车、二手车
     * 
     * @param invoiceId 发票基础表 id
     * @param jsonObject 八戒 api 接口返回的发票 json 数据
     * @param req 基础请求信息
     * @return 统一发票货物详情数据传输对象列表
     */
    @Transactional(rollbackFor = Exception.class)
    public List<ZbjInvoiceUnifiedGoodsDTO> saveGeneralGoods(Integer invoiceId, JSONObject jsonObject, BaseReqObj req) {
        JSONArray goodsData = jsonObject.getJSONArray("goodsData");
        List<ZbjInvoiceUnifiedGoods> goodsList = goodsData.toJavaList(ZbjInvoiceUnifiedGoods.class);
        goodsList.forEach(t -> {
            t.setInvoiceId(invoiceId);
            t.setChannel(req.getChannel());
            t.setGmtCreate(LocalDateTime.now());
            t.setCreateBy(req.getOperationUserId());
            t.setGmtModified(LocalDateTime.now());
            t.setModifiedBy(req.getOperationUserId());
            unifiedGoodsMapper.insert(t);
        });
        return BeanUtil.mapList(mapper, goodsList, ZbjInvoiceUnifiedGoodsDTO.class);
    }

    /**
     * 机动车销售统一发票商品明细列表
     * 
     * @param invoiceId 发票基础表 id
     * @param jsonObject 八戒 api 接口返回的发票 json 数据
     * @param req 基础请求信息
     * @return 机动车货物详情数据传输对象列表
     */
    @Transactional(rollbackFor = Exception.class)
    public List<ZbjInvoiceMotorVehiclesGoodsDTO> saveMotorVehiclesGoods(Integer invoiceId, JSONObject jsonObject,
        BaseReqObj req) {
        JSONArray goodsData = jsonObject.getJSONArray("goodsData");
        List<ZbjInvoiceMotorVehiclesGoods> goodsList = goodsData.toJavaList(ZbjInvoiceMotorVehiclesGoods.class);
        goodsList.forEach(t -> {
            t.setInvoiceId(invoiceId);
            t.setChannel(req.getChannel());
            t.setCreateBy(req.getOperationUserId());
            t.setGmtCreate(LocalDateTime.now());
            t.setGmtModified(LocalDateTime.now());
            t.setModifiedBy(req.getOperationUserId());
            motorVehiclesGoodsMapper.insert(t);
        });
        return BeanUtil.mapList(mapper, goodsList, ZbjInvoiceMotorVehiclesGoodsDTO.class);
    }

    /**
     * 二手车销售统一发票商品明细列表
     *
     * @param invoiceId 发票基础表 id
     * @param jsonObject 八戒 api 接口返回的发票 json 数据
     * @param req 基础请求信息
     * @return 二手车货物详情数据传输对象列表
     */
    @Transactional(rollbackFor = Exception.class)
    public List<ZbjInvoiceUsedCarGoodsDTO> saveUsedCarGoods(Integer invoiceId, JSONObject jsonObject, BaseReqObj req) {
        JSONArray goodsData = jsonObject.getJSONArray("goodsData");
        List<ZbjInvoiceUsedCarGoods> goodsList = goodsData.toJavaList(ZbjInvoiceUsedCarGoods.class);
        goodsList.forEach(t -> {
            t.setInvoiceId(invoiceId);
            t.setChannel(req.getChannel());
            t.setGmtCreate(LocalDateTime.now());
            t.setCreateBy(req.getOperationUserId());
            t.setModifiedBy(req.getOperationUserId());
            t.setGmtModified(LocalDateTime.now());
            usedCarGoodsMapper.insert(t);
        });
        return BeanUtil.mapList(mapper, goodsList, ZbjInvoiceUsedCarGoodsDTO.class);
    }

}
